#ifndef POSITIONCACHE_H
#define POSITIONCACHE_H


#include "Selection.h"


#ifdef SCI_NAMESPACE
namespace Scintilla {
#endif

  static inline bool IsEOLChar( char ch ) {
    return ( ch == '\r' ) || ( ch == '\n' );
  }


  class LineLayout {
    private:
      friend class LineLayoutCache;
      int *lineStarts;
      int lenLineStarts;

      int lineNumber;
      bool inCache;
    public:
      enum { wrapWidthInfinite = 0x7ffffff };
      int maxLineLength;
      int numCharsInLine;
      int numCharsBeforeEOL;
      enum validLevel { llInvalid, llCheckTextAndStyle, llPositions, llLines } validity;
      int xHighlightGuide;
      bool highlightColumn;
      bool containsCaret;
      int edgeColumn;
      char *chars;
      unsigned char *styles;
      XYPOSITION *positions;
      char bracePreviousStyles[2];


      Range hotspot;


      int widthLine;
      int lines;
      XYPOSITION wrapIndent;
      explicit LineLayout( int maxLineLength_ );
      virtual ~LineLayout();
      void Resize( int maxLineLength_ );
      void Free();
      void Invalidate( validLevel validity_ );
      int LineStart( int line ) const;
      int LineLastVisible( int line ) const;
      Range SubLineRange( int line ) const;
      bool InLine( int offset, int line ) const;
      void SetLineStart( int line, int start );
      void SetBracesHighlight( Range rangeLine, const Position braces[],
                               char bracesMatchStyle, int xHighlight, bool ignoreStyle );
      void RestoreBracesHighlight( Range rangeLine, const Position braces[], bool ignoreStyle );
      int FindBefore( XYPOSITION x, int lower, int upper ) const;
      int FindPositionFromX( XYPOSITION x, Range range, bool charPosition ) const;
      Point PointFromPosition( int posInLine, int lineHeight ) const;
      int EndLineStyle() const;
  };


  class LineLayoutCache {
      int level;
      std::vector<LineLayout *>cache;
      bool allInvalidated;
      int styleClock;
      int useCount;
      void Allocate( size_t length_ );
      void AllocateForLevel( int linesOnScreen, int linesInDoc );
    public:
      LineLayoutCache();
      virtual ~LineLayoutCache();
      void Deallocate();
      enum {
        llcNone = SC_CACHE_NONE,
        llcCaret = SC_CACHE_CARET,
        llcPage = SC_CACHE_PAGE,
        llcDocument = SC_CACHE_DOCUMENT
      };
      void Invalidate( LineLayout::validLevel validity_ );
      void SetLevel( int level_ );
      int GetLevel() const { return level; }
      LineLayout *Retrieve( int lineNumber, int lineCaret, int maxChars, int styleClock_,
                            int linesOnScreen, int linesInDoc );
      void Dispose( LineLayout *ll );
  };

  class PositionCacheEntry {
      unsigned int styleNumber: 8;
      unsigned int len: 8;
      unsigned int clock: 16;
      XYPOSITION *positions;
    public:
      PositionCacheEntry();
      ~PositionCacheEntry();
      void Set( unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_, unsigned int clock_ );
      void Clear();
      bool Retrieve( unsigned int styleNumber_, const char *s_, unsigned int len_, XYPOSITION *positions_ ) const;
      static unsigned int Hash( unsigned int styleNumber_, const char *s, unsigned int len );
      bool NewerThan( const PositionCacheEntry &other ) const;
      void ResetClock();
  };

  class Representation {
    public:
      std::string stringRep;
      explicit Representation( const char *value = "" ) : stringRep( value ) {
      }
  };

  typedef std::map<int, Representation> MapRepresentation;

  class SpecialRepresentations {
      MapRepresentation mapReprs;
      short startByteHasReprs[0x100];
    public:
      SpecialRepresentations();
      void SetRepresentation( const char *charBytes, const char *value );
      void ClearRepresentation( const char *charBytes );
      const Representation *RepresentationFromCharacter( const char *charBytes, size_t len ) const;
      bool Contains( const char *charBytes, size_t len ) const;
      void Clear();
  };

  struct TextSegment {
    int start;
    int length;
    const Representation *representation;
    TextSegment( int start_ = 0, int length_ = 0, const Representation *representation_ = 0 ) :
      start( start_ ), length( length_ ), representation( representation_ ) {
    }
    int end() const {
      return start + length;
    }
  };


  class BreakFinder {
      const LineLayout *ll;
      Range lineRange;
      int posLineStart;
      int nextBreak;
      std::vector<int> selAndEdge;
      unsigned int saeCurrentPos;
      int saeNext;
      int subBreak;
      const Document *pdoc;
      EncodingFamily encodingFamily;
      const SpecialRepresentations *preprs;
      void Insert( int val );

      BreakFinder( const BreakFinder & );
    public:


      enum { lengthStartSubdivision = 300 };

      enum { lengthEachSubdivision = 100 };
      BreakFinder( const LineLayout *ll_, const Selection *psel, Range rangeLine_, int posLineStart_,
                   int xStart, bool breakForSelection, const Document *pdoc_, const SpecialRepresentations *preprs_ );
      ~BreakFinder();
      TextSegment Next();
      bool More() const;
  };

  class PositionCache {
      std::vector<PositionCacheEntry> pces;
      unsigned int clock;
      bool allClear;

      PositionCache( const PositionCache & );
    public:
      PositionCache();
      ~PositionCache();
      void Clear();
      void SetSize( size_t size_ );
      size_t GetSize() const { return pces.size(); }
      void MeasureWidths( Surface *surface, const ViewStyle &vstyle, unsigned int styleNumber,
                          const char *s, unsigned int len, XYPOSITION *positions, Document *pdoc );
  };

  inline bool IsSpaceOrTab( int ch ) {
    return ch == ' ' || ch == '\t';
  }

  #ifdef SCI_NAMESPACE
}
  #endif

#endif
